package com.webank.maling.documentation.repository.graph.support;

import com.webank.maling.base.model.MethodInfo;
import com.webank.maling.base.util.ContentCompressor;
import com.vesoft.nebula.client.graph.data.Node;
import com.vesoft.nebula.client.graph.data.Relationship;
import com.vesoft.nebula.client.graph.data.ValueWrapper;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Map;

@Slf4j
@UtilityClass
public class GraphSupport {

    /**
     * * 将Vertex解析为MethodInfo
     */
    public MethodInfo parseVertexToMethodInfo(Node node) {
        try {
            String methodId = node.getId().asString();
            var properties = node.properties("function");

            String fullName = getStringProperty(properties, "full_name");
            String methodName = getStringProperty(properties, "name");

            String classFullName = null;
            if (StringUtils.isNotBlank(fullName)) {
                String[] vars = fullName.split("#");
                classFullName = vars[0];
            }
            return MethodInfo.builder()
                    .methodId(methodId)
                    .methodName(methodName)
                    .fullName(fullName)
                    .signature(fullName) // 使用fullName作为签名
                    .className(extractClassName(classFullName))
                    .packageName(extractPackageName(classFullName))
                    .visibility(getStringProperty(properties, "visibility"))
                    .isStatic(getBooleanProperty(properties, "is_static"))
                    .isAbstract(getBooleanProperty(properties, "is_abstract"))
                    .isFinal(getBooleanProperty(properties, "is_final"))
                    .isEntryPoint(getBooleanProperty(properties, "is_entry_point"))
                    .returnType(getStringProperty(properties, "return_type"))
                    .parameterTypes(getStringProperty(properties, "parameter_types"))
                    .exceptionTypes(getStringProperty(properties, "exception_types"))
                    .sourceFile(getStringProperty(properties, "source_file"))
                    .startLine(getIntegerProperty(properties, "line_start"))
                    .endLine(getIntegerProperty(properties, "line_end"))
                    .complexityScore(getIntegerProperty(properties, "complexity"))
                    .description(getStringProperty(properties, "description"))
                    .content(ContentCompressor.decompress(getStringProperty(properties, "content")))
                    .build();

        } catch (Exception e) {
            log.warn("解析Vertex为MethodInfo时发生错误", e);
            return null;
        }
    }

    private String extractClassName(String classFullName) {
        if (classFullName == null || classFullName.isEmpty()) {
            return null;
        }
        int lastDotIndex = classFullName.lastIndexOf('.');
        return classFullName.substring(lastDotIndex + 1);
    }

    private String extractPackageName(String classFullName) {
        if (classFullName == null || classFullName.isEmpty()) {
            return null;
        }
        int lastDotIndex = classFullName.lastIndexOf('.');
        if (lastDotIndex > 0) {
            return classFullName.substring(0, lastDotIndex);
        } else {
            return classFullName;
        }
    }

    private String getStringProperty(Map<String, ValueWrapper> properties, String key) throws UnsupportedEncodingException {
        ValueWrapper wrapper = properties.get(key);
        return (wrapper != null && wrapper.isString()) ? wrapper.asString() : null;
    }

    private Boolean getBooleanProperty(Map<String, ValueWrapper> properties, String key) {
        ValueWrapper wrapper = properties.get(key);
        return (wrapper != null && wrapper.isBoolean()) ? wrapper.asBoolean() : null;
    }

    private Integer getIntegerProperty(Map<String, ValueWrapper> properties, String key) {
        ValueWrapper wrapper = properties.get(key);
        return (wrapper != null && wrapper.isLong()) ? (int) wrapper.asLong() : null;
    }

    public String getEdgeStringProperty(Relationship edge, String key) {
        try {
            var properties = edge.properties();
            ValueWrapper wrapper = properties.get(key);
            return (wrapper != null && wrapper.isString()) ? wrapper.asString() : null;
        } catch (Exception e) {
            return null;
        }
    }

    public Integer getEdgeIntProperty(Relationship edge, String key) {
        try {
            var properties = edge.properties();
            ValueWrapper wrapper = properties.get(key);
            return (wrapper != null && wrapper.isLong()) ? (int) wrapper.asLong() : null;
        } catch (Exception e) {
            return null;
        }
    }
}
